package com.github.framework.aop;

import com.github.framework.aop.aspect.Advice;
import com.github.framework.aop.intercept.MethodInvocation;
import com.github.framework.aop.support.AdviceSupport;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.aop.support.AopUtils;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;

/**
 * Created by Tom.
 */
public class JdkDynamicAopProxy implements AopProxy,InvocationHandler {
    private AdviceSupport advices;

    public JdkDynamicAopProxy(AdviceSupport advices) {
        this.advices = advices;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 含有各个阶段的切面

        // Get the interception chain for this method.
        //获取可以应用到此方法上的Interceptor列表
        List<Object> chain = this.advices.getInterceptorsAndDynamicInterceptionAdvice(method, this.advices.getTargetClass());

        MethodInvocation mi = new MethodInvocation(proxy, this.advices.getTarget(), method, args, this.advices.getTargetClass(), chain);
        // Proceed to the joinpoint through the interceptor chain.
        return mi.proceed();
//        Map<String, Advice> advices = config.getAdvices(method,null);

//        Object returnValue;
//        try {
//            invokeAdivce(advices.get("before"));
//
//            returnValue = method.invoke(this.config.getTarget(),args);
//
//            invokeAdivce(advices.get("after"));
//        }catch (Exception e){
//            invokeAdivce(advices.get("afterThrow"));
//            throw e;
//        }
//
//        return returnValue;
    }

    private void invokeAdivce(Advice advice) {
        try {
            advice.getAdviceMethod().invoke(advice.getAspect());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),this.advices.getTargetClass().getInterfaces(),this);
    }

    @Override
    public Object getProxy(ClassLoader loader) {
        return Proxy.newProxyInstance(loader,this.advices.getTargetClass().getInterfaces(),this);
    }
}
